package com.glsc.ngateway.oaflow.service;

import com.alibaba.fastjson.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.glsc.ngateway.common.api.common.enums.ExceptionConstant;
import com.glsc.ngateway.common.api.common.enums.GatewayConstant;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrDeptDto;
import com.glsc.ngateway.common.api.ldap.feign.IFeignLdapService;
import com.glsc.ngateway.common.api.oaflow.dto.FixedincomeGDto;
import com.glsc.ngateway.common.api.oaflow.dto.FixedincomeProcessDto;
import com.glsc.ngateway.common.api.oaflow.dto.other.FlowObject;
import com.glsc.ngateway.common.api.oaflow.resp.InterfaceResponse;
import com.glsc.ngateway.common.xir.domain.TsysUser;
import com.glsc.ngateway.common.xir.repo.TsysUserRepository;
import com.glsc.ngateway.oaflow.constant.FixedIncomeConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.SystemConfig;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TFixedincomeProcess;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TFixedincomeProcessRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.SystemConfigRepository;
import com.glsc.ngateway.oaflow.exception.BusinessException;
import com.glsc.ngateway.oaflow.utils.*;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 衡泰 固收 移动审批接口
 */
@Service
public class FixedIncomeService {

    private static final Logger logger = LoggerFactory.getLogger(FixedIncomeService.class);

    private static final String key = "qJzGEh6hESZDVJeCnFPGuxza";

    @Autowired
    private MetaFlowService metaFlowService;
    @Autowired
    AddFlowService addFlowService;

    @Autowired
    TFixedincomeProcessRepository tFixedincomeProcessRepository;


    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${fixedincome.username}")
    public String username;
    @Value("${fixedincome.password}")
    public String password;
    @Value("${fixedincome.url}")
    public String url;
    @Value("${fixedincome.ip}")
    public String ip;
    @Value("${fixedincome.port}")
    public Integer port;
    @Value("${fixedincome.workflowId}")
    public String fixedIncomeWorkflowId;
    @Value("${fixedincome.opearWorkflowId}")
    public String fixedIncomeOpearWorkflowId;//衡泰资金运营部移动审批
    @Value("${fixedincome.creater}")
    public String creater;

    @Resource
    private SystemConfigRepository systemConfigRepository;
    @Resource
    private TsysUserRepository tsysUserRepository;
    @Resource
    private IFeignLdapService feignLdapService;

    ObjectMapper mapper = new ObjectMapper();

    public List<TFixedincomeProcess> findAllOaToDeal() {
        return tFixedincomeProcessRepository.findByStatus("0");
    }

    /**
     * 终止oa流程
     * @param requestid
     * @return
     */
    public String endOaFlow(String requestid) {
        Map<String, String> map = addFlowService.endOaFlow(requestid);
        logger.info("endOaFlowmap{}",map);
        return JSON.toJSONString(InterfaceResponse.returnSuccss(map));
    }

    /**
     * 创建oa固收关联交易流程
     *
     * @param userId
     * @param json
     * @param submitueser
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException
     */
    public String createFixedIncomeProcessRelate(String userId, List<String> json, String submitueser) throws Exception {

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("creater", creater);
        dataMap.put("applicant", creater);
        dataMap.put("spr", userId);
        dataMap.put("title", "衡泰移动审批-关联交易(" + json.size() + "笔)");
        dataMap.put("applyDate", DateUtils.getCurrentDate("yyyy-MM-dd"));

        StringBuffer sb = new StringBuffer();
        logger.info("createFixedIncomeProcessRelate{}",json);
        for (String single : json) {
            JSONObject js = JSONObject.parseObject(single);
            JSONArray r = js.getJSONArray("R");

            Map<String, Object> rMap = new HashMap<>();
            if (r != null && !r.isEmpty()) {
                r.forEach(object -> {
                    if (object == null) {
                        return;
                    }
                    JSONObject jsonObject = (JSONObject) object;
                    if (jsonObject.getString("text") == null) {
                        return;
                    }
                    rMap.put(jsonObject.getString("NAME"), jsonObject.getString("text"));
                });
            }
            logger.info("rmap"+rMap.toString());
            sb.append(createElements(js, rMap, ""));
        }
        dataMap.put("elements", sb.toString());
        String result = createOaflow(dataMap, getWorkFlowId(submitueser));
        return result;
    }

    /**
     * 创建固收流程
     *
     * @param userId
     * @param json
     * @param submitueser
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException
     */
    public String createFixedIncomeProcess(String userId, String json, String submitueser) throws Exception {

        logger.info("String userId{}, String json{}",userId,json);
        Map<String, Object> dataMap = new HashMap<>();
//        dataMap.put("creater", "sysamin");
//        dataMap.put("applicant", "suw");
        dataMap.put("creater", creater);
        dataMap.put("applicant", creater);
        dataMap.put("spr", userId);
        //dataMap.put("title", "衡泰测试");
        dataMap.put("applyDate", DateUtils.getCurrentDate("yyyy-MM-dd"));
        JSONObject js = JSONObject.parseObject(json);
        logger.info("js{}",js);

        dataMap.put("title", "衡泰移动审批-单笔-" + js.getString("TY"));

        JSONArray r = js.getJSONArray("R");
        Map<String, Object> rMap = new HashMap<>();
        if (r != null && !r.isEmpty()) {
            r.forEach(object -> {
                if (object == null) {
                    return;
                }
                JSONObject jsonObject = (JSONObject) object;
                if (jsonObject.getString("text") == null) {
                    return;
                }
                rMap.put(jsonObject.getString("NAME"), jsonObject.getString("text"));
            });
        }
        logger.info("rmp"+rMap.toString());


        dataMap.put("elements", createElements(js, rMap, ""));
        String result = createOaflow(dataMap, getWorkFlowId(submitueser));
        return result;
    }

    /**
     * @param userId
     * @param json
     * @param groupName
     * @param submitueser
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException
     */
    public String createFixedIncomeProcessGroup(String userId, List<String> json, String groupName, String submitueser) throws Exception {
        logger.info("String userId{}, List<String> json{}, String groupName{}",userId, json, groupName);

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("creater", creater);
        dataMap.put("applicant", creater);
        dataMap.put("spr", userId);
        dataMap.put("title", "衡泰移动审批-组合(" + json.size() + "笔)-" + groupName);
        dataMap.put("applyDate", DateUtils.getCurrentDate("yyyy-MM-dd"));

        StringBuffer sb = new StringBuffer();
        for (String single : json) {
            JSONObject js = JSONObject.parseObject(single);
            JSONArray r = js.getJSONArray("R");

            Map<String, Object> rMap = new HashMap<>();
            if (r != null && !r.isEmpty()) {
                r.forEach(object -> {
                    if (object == null) {
                        return;
                    }
                    JSONObject jsonObject = (JSONObject) object;
                    if (jsonObject.getString("text") == null) {
                        return;
                    }
                    rMap.put(jsonObject.getString("NAME"), jsonObject.getString("text"));
                });
            }
            logger.info("rmaps"+rMap.toString());
            sb.append(createElements(js, rMap, groupName));
        }
        dataMap.put("elements", sb.toString());
        String result = createOaflow(dataMap, getWorkFlowId(submitueser));
        return result;
    }

//"ActiveRoleName":"交易主管"
//    "OR":"2021-12-16","TY":"买入","ISCCROLE":"False","ActiveStep":"步骤2",
//            "CASHDIRECTION":"0","NID":"2377651","GR":"2377651,ydsp1","ID":"251246","TID":"2377649"

    private String createElements(JSONObject js, Map<String, Object> rMap, String groupName) {
        logger.info("JSONObject js{}, Map<String, Object> rMap{], String groupName{}",js, rMap, groupName);
        StringBuffer sb = new StringBuffer();
        Map<String, String> mapType = JSON.parseObject(String.valueOf(js), Map.class);
        int count = 0;
        for (Map.Entry<String, String> entry : mapType.entrySet()) {
            if (!entry.getKey().equals("R")) {
                String keyhead = FixedIncomeConstant.keyToElementMap.get(entry.getKey());
                if (!StringUtils.isEmpty(keyhead)) {
                    count++;
                    String oneElementNode = keyhead + "=" + entry.getValue();
                    if (count % 2 == 0) {
                        sb.append(oneElementNode).append("<br/>");
                    } else {
                        sb.append(oneElementNode).append(generateBlank(oneElementNode));
                    }
                }
            }
        }
        sb.append("<br/>");

        if (!StringUtils.isEmpty(groupName)) {
            sb.append("<strong>组合名称=</strong>").append(groupName).append("<br/>");
        }

        int count2 = 0;
        for (Map.Entry<String, Object> rm : rMap.entrySet()) {
            if (!rm.getKey().equals("R")) {
                count2++;
                String oneElement = rm.getKey() + "=" + rm.getValue();
                //奇偶？
                if (count2 % 2 == 0) {
                    sb.append(oneElement).append("<br/>");
                } else {
                    sb.append(oneElement).append(generateBlank(oneElement));
                }
            }
        }
        if (count2 % 2 != 0) {
            sb.append("<br/>");
        }

//
//        for (Map.Entry<String, Object> rm : rMap.entrySet()) {
//            if (!rm.getKey().equals("R")) {
//                String oneElement = rm.getKey() + "=" + rm.getValue();
//                sb.append(oneElement).append("<br/>");
//            }
//        }
        sb.append("------------------------------------------------------------------------").append("<br/>");
        return sb.toString();
    }

    private String generateBlank(String oneElement) {
        int blackSize = 43 - getTextSize(oneElement);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < blackSize; i++) {
            sb.append("&nbsp;");
        }
        return sb.toString();
    }

    /**
     * 对其格式，计算文本大小
     * @param s
     * @return
     */
    public int getTextSize(String s) {
        double len = 0;
        char[] ss = s.toCharArray();
        for (int i = 0; i < ss.length; i++) {
            if (isContainChinese(ss[i])) {
                len += 3;
            } else if (isNumeric(ss[i])) {
                len += 2;
            } else if (ss[i] >= 'A' && ss[i] <= 'Z') {
                len += 2.5;
            } else if (ss[i] >= 'a' && ss[i] <= 'z') {
                len += 2;
            } else if (String.valueOf(ss[i]).equals("%")) {
                len += 3;
            } else if (String.valueOf(ss[i]).equals("(") || String.valueOf(ss[i]).equals(")")) {
                len += 1;
            } else if (String.valueOf(ss[i]).equals(".") || String.valueOf(ss[i]).equals(",")) {
                len += 1;
            } else if (String.valueOf(ss[i]).equals("+")) {
                len += 2.5;
            } else if (String.valueOf(ss[i]).equals("-")) {
                len += 1.5;
            } else if (String.valueOf(ss[i]).equals("=")) {
                len += 2.5;
            } else {
                len += 1;
            }
        }
        return (int) Math.round(len);
    }

    public static boolean isNumeric(char str) {
        if (!Character.isDigit(str)) {
            return false;
        }
        return true;
    }

    /**
     * 2  * 判断字符是否是中文，能校验是否为中文标点符号
     * 3  *
     * 4  * @param str 待校验字符
     * 5  * @return 是否为中文
     * 6
     */
    public boolean isContainChinese(char str) {
        // 中文字
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(String.valueOf(str));
        if (m.find()) {
            return true;
        }
        // 中文标点符号
        p = Pattern.compile("[\uFF01]|[\uFF0C-\uFF0E]|[\uFF1A-\uFF1B]|[\uFF1F]|[\uFF08-\uFF09]|[\u3001-\u3002]|[\u3010-\u3011]|[\u201C-\u201D]|[\u2013-\u2014]|[\u2018-\u2019]|[\u2026]|[\u3008-\u300F]|[\u3014-\u3015]");
        m = p.matcher(String.valueOf(str));
        return m.find();
    }

    /**
     * 调用衡泰接口获取领导出差状态
     * @param key
     * @return
     */
    public List<String> getTripList(String key) {

        List<String> triplist = new ArrayList<>();

        try {
            String requestBody = EncryptUtils.encryptString(getTripListHeader(key));
            HttpHeaders loginHeader = header(requestBody.getBytes().length, FixedIncomeConstant.TRIPLIST_INTERFACENAME);
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, loginHeader);
            logger.info("衡泰获取出差人员接口请求参数:" + request);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);
            logger.info("衡泰获取出差人员接口返回原始报文:" + postForEntity.getBody());
            String response = postForEntity.getBody();
            JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
            JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject("MobileGetAllBusinessUserResponse").getJSONObject("MobileGetAllBusinessUserResult");
            String code = result.getJSONObject("rt").getJSONObject("RE").getString("RC");
            if ("0".equals(code)) {
                Object obj1 = result.getJSONObject("rt").get("DATA");
                if (obj1 == null) {
                    logger.info("wuren");
                    //无人出差，继续
                } else {
                    Object obj = result.getJSONObject("rt").getJSONObject("DATA").get("MobileData");
                    logger.info("obj{}",obj);
                    if (obj != null) {
                        if (obj instanceof JSONObject) {
                            JSONObject ob = result.getJSONObject("rt").getJSONObject("DATA").getJSONObject("MobileData");
                            triplist.add(ob.getString("ID"));
                        } else if (obj instanceof JSONArray) {
                            JSONArray array = result.getJSONObject("rt").getJSONObject("DATA").getJSONArray("MobileData");
                            if (array != null) {
                                for (int i = 0; i < array.size(); i++) {
                                    JSONObject ob = array.getJSONObject(i);
                                    triplist.add(ob.getString("ID"));
                                }
                            }
                        }
                    }
                }
            } else {
                //出差接口返回不是0，就什么也不做
                logger.error("衡泰获取出差人员接口返回异常，请查看！" + postForEntity.getBody());
                triplist.add("error");
            }
            return triplist;
        } catch (Exception e) {
            logger.error("衡泰获取出差人员接口异常，请查看。", e);
            throw new RuntimeException("衡泰获取出差人员接口异常，请查看。");
        }
    }

    @Transactional
    public List<FixedincomeGDto> getGroupCode(String key) {

        List<FixedincomeGDto> grouplist = new ArrayList<>();

        try {
            String requestBody = EncryptUtils.encryptString(getGroupCodeHeader(key));
            HttpHeaders loginHeader = header(requestBody.getBytes().length, FixedIncomeConstant.GROUPCODE_INTERFACENAME);
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, loginHeader);
            logger.info("衡泰获取组合请求参数:" + request);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);
            logger.info("衡泰获取组合接口返回原始报文:" + postForEntity.getBody());
            String response = postForEntity.getBody();
            JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
            JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject("MobileGetTaskNodeGroupResponse").getJSONObject("MobileGetTaskNodeGroupResult");
            String code = result.getJSONObject("rt").getJSONObject("RE").getString("RC");
            if ("0".equals(code)) {
                Object obj = result.getJSONObject("rt").get("G");
                logger.info("obj{}",obj);
                if (obj != null) {
                    if (obj instanceof JSONObject) {
                        JSONObject ob = result.getJSONObject("rt").getJSONObject("G");
                        FixedincomeGDto gDto = JSONObject.parseObject(ob.toJSONString(), FixedincomeGDto.class);
                        grouplist.add(gDto);
                    } else if (obj instanceof JSONArray) {
                        JSONArray array = result.getJSONObject("rt").getJSONArray("G");
                        if (array != null) {
                            for (int i = 0; i < array.size(); i++) {
                                JSONObject ob = array.getJSONObject(i);
                                FixedincomeGDto gDto = JSONObject.parseObject(ob.toJSONString(), FixedincomeGDto.class);
                                grouplist.add(gDto);
                            }
                        }
                    }
                }
            }

            //查询网关记录待处理的node，如果接口代办没有，说明这个node已经被处理，需要调oa去归档
            List<TFixedincomeProcess> waitToDeal = tFixedincomeProcessRepository.getGroupToDeal();
            logger.info("waitToDeal{}",waitToDeal);
            for (TFixedincomeProcess wait : waitToDeal) {
                boolean isFind = false;
                for (FixedincomeGDto dto : grouplist) {
                    if (dto.getC().equals(wait.getGroupId())) {
                        isFind = true;
                        break;
                    }
                }
                logger.info("isFind{}",isFind);
                if (!isFind) {
                    logger.info("网关记录里有未处理的组合指令，衡泰已经没有这条待办，说明可能在衡泰已经撤单。记录状态。 组合指令nodeid= " + wait.getNodeId());
                    wait.setStatus("4");
                    wait.setFixStatus("1");
                    tFixedincomeProcessRepository.save(wait);
                }
            }
            return grouplist;
        } catch (Exception e) {
            logger.error("衡泰获取组合接口异常，请查看。", e);
            throw new RuntimeException("衡泰获取组合接口异常，请查看。");
        }
    }

    @Transactional
    public void searchGroupTaskToDeal(List<String> tripList, FixedincomeGDto group, String key) {

        SystemConfig config = systemConfigRepository.findByConfigCode(DictConstant.FIXED_ROLE_OA_MAP);
        String mapValue = config.getConfigValue();
        JSONObject  jsonObject = JSONObject.parseObject(mapValue);
        Map<String,String> sysAccountMap = JSONObject.parseObject(jsonObject.toJSONString(),new TypeReference<Map<String,String>>(){});

        SystemConfig configAccount = systemConfigRepository.findByConfigCode(DictConstant.FIXED_ROLE_ACCOUNT_MAP);
        String mapValueAccount = configAccount.getConfigValue();
        JSONObject  jsonObjectAccount = JSONObject.parseObject(mapValueAccount);
        Map<String,String> roleToAccontMap = JSONObject.parseObject(jsonObjectAccount.toJSONString(),new TypeReference<Map<String,String>>(){});


        logger.info("List<String> tripList{}, FixedincomeGDto group{}, String key{}",tripList, group, key);
        //group为所有领导的，包括固收和资金
        try {
            String total = "0";
            //设置默认总页数1
            int pageNumberTotal = 1;

            for (int page = 1; page <= pageNumberTotal; page++) {

                String requestBody = EncryptUtils.encryptString(searchGroupTaskHeader(key, String.valueOf(page), group.getC()));
                HttpHeaders header = header(requestBody.getBytes().length, FixedIncomeConstant.SEARCH_INTERFACENAME);
                logger.info("header"+header.toString());
                // 组装发送postForEntity请求
                HttpEntity<String> request = new HttpEntity<>(requestBody, header);
                logger.info("request"+request);
                ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);

                logger.info("post"+postForEntity);
                String code = getCodeFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
                //取得总条数
                total = getTotalFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
                //算出总页数
                pageNumberTotal = Integer.parseInt(total);

                if ("0".equals(code)) {
                    //group为所有领导的，包括固收和资金
                    List<FixedincomeProcessDto> rowlist = getRowFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
                    logger.info("rowlist{}",rowlist);
                    if (rowlist != null && rowlist.size() > 0) {
                        //一个接口返回的组合指令，也有可能包含多个流程
                        Map<String, List<FixedincomeProcessDto>> map = rowlist.stream().collect(Collectors.groupingBy(FixedincomeProcessDto::getNID));
                        logger.info("map{}",map);
                        for (Map.Entry<String, List<FixedincomeProcessDto>> row : map.entrySet()) {
                            List<TFixedincomeProcess> batchInsertList = new ArrayList<>();
                            List<String> jsonlist = new ArrayList<>();
                            String nid = "";
                            String roleName = "";
                            if (row != null && row.getValue().size() > 0) {
                                nid = row.getValue().get(0).getNID();
                                roleName = row.getValue().get(0).getActiveRoleName();
                                List<TFixedincomeProcess> exist = tFixedincomeProcessRepository.findByNodeId(nid);
                                logger.info("exist{}",exist);
                                boolean isCreate = true;
                                for (TFixedincomeProcess e : exist) {
                                    //如果状态有不等于4的就不创建流程，4为未操作就归档的废单的流程
                                    if (!"4".equals(e.getStatus())) {
                                        isCreate = false;
                                        break;
                                    }
                                }
                                logger.info("isCreate{}",isCreate);
                                if (isCreate) {
                                    //查询待办，如果网关没有记录，则记录，并在oa创建相关流程
                                    for (FixedincomeProcessDto f : row.getValue()) {
                                        //该角色是出差，发起移动审批
                                        if (tripList.contains(roleToAccontMap.get(f.getActiveRoleName()))) {
                                            TFixedincomeProcess process = new TFixedincomeProcess();
                                            process.setTaskId(f.getTID());
                                            process.setNodeId(f.getNID());
                                            process.setUserId(sysAccountMap.get(f.getActiveRoleName()));
                                            process.setStatus("0");
                                            process.setTradeId(f.getID());
                                            process.setWorkFlowId(getWorkFlowId(f.getSUBMITUESER()));
                                            process.setBusinessContent(f.getRowJson());
                                            process.setGroupInfo(JSONObject.toJSONString(group));
                                            process.setGroupId(group.getC());
                                            process.setGroupName(group.getN());
                                            batchInsertList.add(process);
                                            jsonlist.add(f.getRowJson());
                                        }
                                    }
                                    logger.info("jsonlist{}",jsonlist);
                                    if (tripList.contains(roleToAccontMap.get(roleName))) {
                                        logger.info(nid + "组合指令去oa创建流程开始");
                                        String oaresult = createFixedIncomeProcessGroup(sysAccountMap.get(roleName), jsonlist, group.getN(),row.getValue().get(0).getSUBMITUESER());
                                        logger.info(nid + "组合指令去oa创建流程结束");
                                        JSONObject js = JSONObject.parseObject(oaresult);

                                        String oacode = js.getString("code");
                                        if ("0".equals(oacode)) {
                                            String requestid = js.getJSONObject("data").getString("requestid");
                                            for (TFixedincomeProcess in : batchInsertList) {
                                                in.setRequestId(requestid);
                                                tFixedincomeProcessRepository.save(in);
                                            }
                                        } else {
                                            logger.error("衡泰移动审批，在oa创建流程失败！ msg=" + oaresult);
                                        }
                                    }
                                } else {
                                    logger.info("如果网关有记录，且这个领导不是出差，那么就要归档了");
                                    //如果网关有记录，且这个领导不是出差，那么就要归档了
                                    for (FixedincomeProcessDto f : row.getValue()) {
                                        if (!tripList.contains(roleToAccontMap.get(f.getActiveRoleName()))) {
                                            List<TFixedincomeProcess> existgroup = tFixedincomeProcessRepository.findByNodeIdAndTradeIdAndStatus(f.getNID(), f.getID(), "0");
                                            logger.info("existgroup{}",existgroup);
                                            if (existgroup != null && existgroup.size() > 0) {
                                                for (TFixedincomeProcess e : existgroup) {
                                                    logger.info(roleToAccontMap.get(f.getActiveRoleName()) + "该领导没有出差，但是oa里面创建了流程，需要对该组合流程进行归档。nodeId=" + f.getNID() + ", requestid=" + e.getRequestId());
                                                    e.setStatus("4");
                                                    e.setFixStatus("1");
                                                    e.setOaStatus("1");
                                                    tFixedincomeProcessRepository.save(e);
                                                    endOaFlow(e.getRequestId());
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                    }
                } else {
                    logger.error("衡泰系统查询组合任务接口返回有误，请查看。res=" + postForEntity.getBody());
                    String newkey = getKeyFromLogin();
                    redisTemplate.opsForValue().set(FixedIncomeConstant.REDIS_FIXEDINCOME_KEY, newkey, 24, TimeUnit.HOURS);
                }
            }
        } catch (Exception e) {
            logger.error("衡泰系统查询组合任务接口异常，请查看。", e);
            throw new RuntimeException("衡泰系统查询组合任务接口异常，请查看。");
        }
    }

    @SneakyThrows
    private String getWorkFlowId(String submitueser) {
        TsysUser tsysUser = tsysUserRepository.findOneByuId(submitueser);
        String mail = tsysUser.getUEmail();
        if (StringUtils.isEmpty(mail)){
            return fixedIncomeWorkflowId;
        }
        String mailString[] = mail.split("@");
        LdapEhrDeptDto dept = feignLdapService.getDepByAccount(mailString[0]).getData();
        if (Objects.isNull(dept)) {
            return Strings.EMPTY;
        }
        String deptName = dept.getDtitle();
        if (deptName.startsWith("资金运营部")){
            return fixedIncomeOpearWorkflowId;
        }else {
            return fixedIncomeWorkflowId;
        }
    }


    @Transactional
    public void searchTaskToDeal(List<String> tripList, String key) {
        SystemConfig config = systemConfigRepository.findByConfigCode(DictConstant.FIXED_ROLE_OA_MAP);
        String mapValue = config.getConfigValue();
        JSONObject  jsonObject = JSONObject.parseObject(mapValue);
        Map<String,String> sysAccountMap = JSONObject.parseObject(jsonObject.toJSONString(),new TypeReference<Map<String,String>>(){});

        SystemConfig configAccount = systemConfigRepository.findByConfigCode(DictConstant.FIXED_ROLE_ACCOUNT_MAP);
        String mapValueAccount = configAccount.getConfigValue();
        JSONObject  jsonObjectAccount = JSONObject.parseObject(mapValueAccount);
        Map<String,String> roleToAccontMap = JSONObject.parseObject(jsonObjectAccount.toJSONString(),new TypeReference<Map<String,String>>(){});


        logger.info("tripList{},key{}",tripList,key);
        try {
            String total = "0";
            //设置默认总页数1
            int pageNumberTotal = 1;

            for (int page = 1; page <= pageNumberTotal; page++) {

                String requestBody = EncryptUtils.encryptString(searchTaskHeader(key, String.valueOf(page)));
                HttpHeaders header = header(requestBody.getBytes().length, FixedIncomeConstant.SEARCH_INTERFACENAME);
                logger.info("headerin"+header.toString());
                // 组装发送postForEntity请求
                HttpEntity<String> request = new HttpEntity<>(requestBody, header);
                logger.info("request"+request);
                ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);

                logger.info("postForEntity"+postForEntity);
                String code = getCodeFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
                //取得总条数
                total = getTotalFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
                //算出总页数
                pageNumberTotal = Integer.parseInt(total);

                logger.info("params:{},{},{}",code,total,pageNumberTotal);

                if ("0".equals(code)) {
                    //系统统一账号全量待办
                    List<FixedincomeProcessDto> rowlist = getRowFromResponse(postForEntity, FixedIncomeConstant.SEARCH_INTERFACENAME);
//*************************************************************************以下为关联交易模块待测试
                    //关联交易nodeid一样，tradeid不一样，按组合显示在一个流程里
                    Map<String, List<FixedincomeProcessDto>> groupBy = rowlist.stream().collect(Collectors.groupingBy(FixedincomeProcessDto::getNID));
                    logger.info("groupBy:{}",groupBy);
                    for (Map.Entry<String, List<FixedincomeProcessDto>> map : groupBy.entrySet()) {
                        logger.info("map:{}",map);
                        logger.info("mapSize:{}",map.getValue().size());
                        if (map.getValue().size() > 1) {
                            //说明是关联交易
                            List<TFixedincomeProcess> batchInsertList = new ArrayList<>();
                            List<String> jsonlist = new ArrayList<>();
                            String nid = map.getValue().get(0).getNID();
                            String roleName = map.getValue().get(0).getActiveRoleName();
                            logger.info("parms{},{},{}",nid,roleName);
                            //该角色是出差，发起移动审批
                            if (tripList.contains(roleToAccontMap.get(roleName))) {
                                List<TFixedincomeProcess> exist = tFixedincomeProcessRepository.findByNodeId(nid);
                                logger.info("exist{}",exist);
                                boolean isCreate = true;
                                for (TFixedincomeProcess e : exist) {
                                    //如果状态有不等于4的就不创建流程，4为未操作就归档的流程
                                    if (!"4".equals(e.getStatus())) {
                                        isCreate = false;
                                        break;
                                    }
                                }
                                if (isCreate) {
                                    logger.info("isCreate{}",isCreate);
                                    for (FixedincomeProcessDto f : map.getValue()) {
                                        TFixedincomeProcess process = new TFixedincomeProcess();
                                        process.setTaskId(f.getTID());
                                        process.setNodeId(f.getNID());
                                        process.setUserId(sysAccountMap.get(f.getActiveRoleName()));
                                        process.setStatus("0");
                                        process.setTradeId(f.getID());
                                        process.setWorkFlowId(getWorkFlowId(f.getSUBMITUESER()));
                                        process.setBusinessContent(f.getRowJson());
                                        batchInsertList.add(process);
                                        jsonlist.add(f.getRowJson());
                                    }
                                    logger.info(nid + "去oa创建关联交易流程开始{},{}",jsonlist,roleName);
                                    String oaresult = createFixedIncomeProcessRelate(sysAccountMap.get(roleName), jsonlist,map.getValue().get(0).getSUBMITUESER());
                                    logger.info(nid + "去oa创建关联交易流程结束");
                                    JSONObject js = JSONObject.parseObject(oaresult);

                                    String oacode = js.getString("code");
                                    if ("0".equals(oacode)) {
                                        String requestid = js.getJSONObject("data").getString("requestid");
                                        for (TFixedincomeProcess in : batchInsertList) {
                                            in.setRequestId(requestid);
                                            tFixedincomeProcessRepository.save(in);
                                        }
                                    } else {
                                        logger.error("衡泰移动审批，在oa创建流程失败！ msg=" + oaresult);
                                    }
                                }
                            } else {
                                List<TFixedincomeProcess> exist = tFixedincomeProcessRepository.findByNodeIdAndStatus(nid, "0");
                                logger.info("exist0{}",exist);
                                if (exist != null && exist.size() > 0) {
                                    for (TFixedincomeProcess e : exist) {
                                        logger.info(roleToAccontMap.get(roleName) + "该领导没有出差，但是oa里面创建了流程，审批还没操作，需要对该流程进行归档。nodeId=" + nid + ", requestid=" + e.getRequestId());
                                        e.setStatus("4");
                                        e.setFixStatus("1");
                                        e.setOaStatus("1");
                                        tFixedincomeProcessRepository.save(e);
                                        endOaFlow(e.getRequestId());
                                    }
                                }
                            }

                        } else if (map.getValue().size() == 1) {
                            //正常单笔交易，按正常逻辑走
                            //查询待办，如果网关没有记录，则记录，并在oa创建相关流程，rowlist为全量所有领导的代办包括固收和资金
                            //for (FixedincomeProcessDto f : rowlist) {
                            //该角色是出差，发起移动审批
                            FixedincomeProcessDto f = map.getValue().get(0);
                            logger.info("f:{}",f);
                            if (tripList.contains(roleToAccontMap.get(f.getActiveRoleName()))) {
                                List<TFixedincomeProcess> exist = tFixedincomeProcessRepository.findByNodeId(f.getNID());
                                logger.info("existNIDS:{}",exist);
                                boolean isCreate = true;
                                for (TFixedincomeProcess e : exist) {
                                    //如果状态有不等于4的就不创建流程，4为未操作就归档的流程
                                    if (!"4".equals(e.getStatus())) {
                                        isCreate = false;
                                        break;
                                    }
                                }
                                logger.info("isCreate:{}",isCreate);
                                if (isCreate) {
                                    TFixedincomeProcess process = new TFixedincomeProcess();
                                    process.setTaskId(f.getTID());
                                    process.setNodeId(f.getNID());
                                    process.setUserId(sysAccountMap.get(f.getActiveRoleName()));
                                    process.setStatus("0");
                                    process.setTradeId(f.getID());
                                    process.setWorkFlowId(getWorkFlowId(f.getSUBMITUESER()));
                                    process.setBusinessContent(f.getRowJson());

                                    logger.info(f.getNID() + "去oa创建流程开始");
                                    String oaresult = createFixedIncomeProcess(sysAccountMap.get(f.getActiveRoleName()), f.getRowJson(),f.getSUBMITUESER());
                                    logger.info(f.getNID() + "去oa创建流程结束");
                                    JSONObject js = JSONObject.parseObject(oaresult);

                                    String oacode = js.getString("code");
                                    if ("0".equals(oacode)) {
                                        String requestid = js.getJSONObject("data").getString("requestid");
                                        process.setRequestId(requestid);
                                        tFixedincomeProcessRepository.save(process);
                                    } else {
                                        logger.error("衡泰移动审批，在oa创建流程失败！ msg=" + oaresult);
                                    }
                                }
                            } else {
                                List<TFixedincomeProcess> exist = tFixedincomeProcessRepository.findByNodeIdAndStatus(f.getNID(), "0");
                                logger.info("existNID{}",exist);
                                if (exist != null && exist.size() > 0) {
                                    for (TFixedincomeProcess e : exist) {
                                        logger.info("constan"+roleToAccontMap.get(f.getActiveRoleName()) + "该领导没有出差，但是oa里面创建了流程，审批还没操作，需要对该流程进行归档。nodeId=" + f.getNID() + ", requestid=" + e.getRequestId());
                                        e.setStatus("4");
                                        e.setFixStatus("1");
                                        e.setOaStatus("1");
                                        tFixedincomeProcessRepository.save(e);
                                        endOaFlow(e.getRequestId());
                                    }
                                }
                            }
                            //}
                        }
                    }
                    //如果不触发分页，则需要走这个逻辑，分页的话无法判断是不是需要归档
                    if (pageNumberTotal == 1) {
                        //查询网关记录待处理的node，如果接口待办没有，说明这个node已经被处理，需要调oa去归档
                        List<TFixedincomeProcess> waitToDeal = tFixedincomeProcessRepository.getSingleToDeal();
                        logger.info("waitToDeal:{}",waitToDeal);
                        for (TFixedincomeProcess wait : waitToDeal) {
                            boolean isFind = false;
                            for (FixedincomeProcessDto dto : rowlist) {
                                if (dto.getNID().equals(wait.getNodeId())) {
                                    isFind = true;
                                    break;
                                }
                            }
                            logger.info("isFind:{}",isFind);
                            if (!isFind) {
                                logger.info("网关记录里有未处理，衡泰已经没有这条待办，说明在衡泰已经撤单或者其他异常情况。记录状态。 nodeid= " + wait.getNodeId());
                                wait.setStatus("4");
                                wait.setFixStatus("1");
                                tFixedincomeProcessRepository.save(wait);
                            }
                        }
                    }
//******************************************************************************************************
                } else {
                    logger.error("衡泰系统查询任务接口返回有误，请查看（有可能key过期重新获取）。res=" + postForEntity.getBody());
                    String newkey = getKeyFromLogin();
                    redisTemplate.opsForValue().set(FixedIncomeConstant.REDIS_FIXEDINCOME_KEY, newkey, 23, TimeUnit.HOURS);
                }
            }
        } catch (Exception e) {
            logger.error("衡泰系统查询任务接口异常，请查看。", e);
            throw new RuntimeException("衡泰系统查询任务接口异常，请查看。");
        }
    }

    //同意继续 1,  拒绝 2  action
    @Transactional
    public void doTaskOaForNoTrip(String requestId) {
        logger.info("无人出差，清理现有未完成oa流程，调用oa归档接口开始。requestId=" + requestId);
        Map<String, String> res = addFlowService.endOaFlow(requestId);
        if (res != null) {
            if (("0").equals(res.get("resultcode"))) {
                logger.info("无人出差，清理现有未完成oa流程，调用oa归档接口成功结束。requestId=" + requestId);
                updateProcessStatusNoTrip(requestId);
            }
        }
    }

    //同意继续 1,  拒绝 2  action
    @Transactional
    public void doTaskOa(String requestId, String action) {
        logger.info("调用oa归档接口开始。requestId=" + requestId + " action=" + action);
        Map<String, String> res = addFlowService.endOaFlow(requestId);
        if (res != null) {
            if (("0").equals(res.get("resultcode"))) {
                logger.info("调用oa归档接口成功结束。requestId=" + requestId + " action=" + action);
                updateProcessStatusOa(requestId, action);
            }
        }
    }

    //同意继续 1,  拒绝 2  action
    public void updateProcessStatus(String nodeId) {
        logger.info("nodeId{}",nodeId);
        List<String> nlist = Arrays.asList(nodeId.split(",").clone());
        for (String n : nlist) {
            List<TFixedincomeProcess> plist = tFixedincomeProcessRepository.findByNodeId(n);
            if (plist != null && plist.size() > 0) {
                for (TFixedincomeProcess p : plist) {
                    p.setFixStatus("1");
                    tFixedincomeProcessRepository.save(p);
                }
            }
        }
    }

    @Transactional
    public void doTask(String nodeId, String action, String key, Set<String> rejectRequestIdList, String userId) {
        logger.info("String nodeId{}, String action{}, String key{}, Set<String> rejectRequestIdList{}, String userId{}",nodeId, action, key, rejectRequestIdList, userId);
        try {
            String requestBody = EncryptUtils.encryptString(approveTaskHeader(key, nodeId, action, userId));
            HttpHeaders header = header(requestBody.getBytes().length, FixedIncomeConstant.DOTASK_INTERFACENAME);
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, header);
            logger.info("request{}",request);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);

            logger.info("psEntity"+postForEntity);
            String code = getCodeFromResponse(postForEntity, FixedIncomeConstant.DOTASK_INTERFACENAME);
            logger.info("code{}",code);
            if ("0".equals(code)) {
                updateProcessStatus(nodeId);

                //如果往衡泰同步拒绝状态，则调用oa归档接口
                if ("2".equals(action)) {
                    logger.info("往衡泰同步拒绝状态，调用oa归档接口");
                    if (rejectRequestIdList != null) {
                        for (String requestid : rejectRequestIdList) {
                            logger.info("往衡泰同步拒绝状态，调用oa归档接口，requestid=" + requestid);
                            endOaFlow(requestid);
                        }
                    }
                }
            }
            //else if ("-1".equals(code)) {
            //不成功也置位，有可能横泰已经清了，oa还在批
            //updateProcessStatus(nodeId, action);
            //logger.error("衡泰系统审批接口返回-1，不成功也置位，有可能横泰已经清了，oa还在批。res=" + postForEntity.getBody());
            // }
            else {
                logger.error("衡泰系统审批接口返回有误，请查看。res=" + postForEntity.getBody());
            }
        } catch (Exception e) {
            logger.error("衡泰系统审批接口异常，请查看。", e);
            throw new RuntimeException("衡泰系统审批接口异常，请查看。");
        }

    }

    public void updateProcessStatusOa(String requestId, String action) {
        List<TFixedincomeProcess> plist = tFixedincomeProcessRepository.findByRequestId(requestId);
        logger.info("plist{},requestid{},action{}",plist,requestId,action);
        if (plist != null && plist.size() > 0) {
            for (TFixedincomeProcess p : plist) {
                p.setOaStatus(action);
                tFixedincomeProcessRepository.save(p);
            }
        }
    }

    public void updateProcessStatusNoTrip(String requestId) {
        List<TFixedincomeProcess> plist = tFixedincomeProcessRepository.findByRequestId(requestId);
        logger.info("plist{},requestid{}",plist,requestId);
        if (plist != null && plist.size() > 0) {
            for (TFixedincomeProcess p : plist) {
                p.setFixStatus("1");
                p.setOaStatus("1");
                //无人出差，状态做4处理
                p.setStatus("4");
                tFixedincomeProcessRepository.save(p);
            }
        }
    }

    public List<TFixedincomeProcess> getProcessToDeal(String fixStatus, String oaStatus) {
        logger.info("fixStatus{},oaStatus{}",fixStatus,oaStatus);
        return tFixedincomeProcessRepository.getProcessToDeal(fixStatus, oaStatus);
    }


    public List<FixedincomeProcessDto> getRowFromResponse(ResponseEntity<String> postForEntity, String
            interfaceName) throws Exception {
        logger.info("ResponseEntity<String> postForEntity{}, String interfaceName{}",postForEntity, interfaceName);
        String response = postForEntity.getBody();
        response = response.replaceAll("#text", "text");
        JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
        JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject(interfaceName + "Response")
                .getJSONObject(interfaceName + "Result");


        List<FixedincomeProcessDto> fp = new ArrayList<>();
        Object row = result.getJSONObject("rt").get("ROW");
        if (row == null){
            logger.info("fpnull{}",fp);
            return fp;
        }
        JSONValidator validator = JSONValidator.from(result.getJSONObject("rt").getString("ROW"));
        JSONValidator.Type jsonType = validator.getType();
        logger.info("jsonType{}",jsonType);
        if (jsonType == JSONValidator.Type.Object) {
            JSONObject ob = result.getJSONObject("rt").getJSONObject("ROW");
            FixedincomeProcessDto one = JSONObject.parseObject(ob.toJSONString(), FixedincomeProcessDto.class);
            one.setRowJson(ob.toJSONString());
            fp.add(one);
        } else if (jsonType == JSONValidator.Type.Array) {
            JSONArray array = result.getJSONObject("rt").getJSONArray("ROW");
            // fp = JSONObject.parseArray(array.toJSONString(), FixedincomeProcessDto.class);
            for (int i = 0; i < array.size(); i++) {
                JSONObject ob = array.getJSONObject(i);
                FixedincomeProcessDto one = JSONObject.parseObject(ob.toJSONString(), FixedincomeProcessDto.class);
                one.setRowJson(ob.toJSONString());
                fp.add(one);
            }
        } else {
            throw new IllegalArgumentException(result.getJSONObject("rt").getString("ROW"));
        }


//        Integer count = result.getJSONObject("rt").getJSONObject("RE").getInteger("RSCOUNT");
//        logger.info("count{}",count);
//        //条数1和大于1 格式不一样 分别处理
//        if (count > 1) {
//            JSONArray array = result.getJSONObject("rt").getJSONArray("ROW");
//            // fp = JSONObject.parseArray(array.toJSONString(), FixedincomeProcessDto.class);
//            for (int i = 0; i < array.size(); i++) {
//                JSONObject ob = array.getJSONObject(i);
//                FixedincomeProcessDto one = JSONObject.parseObject(ob.toJSONString(), FixedincomeProcessDto.class);
//                one.setRowJson(ob.toJSONString());
//                fp.add(one);
//            }
//        } else if (count == 1) {
//            JSONObject ob = result.getJSONObject("rt").getJSONObject("ROW");
//            FixedincomeProcessDto one = JSONObject.parseObject(ob.toJSONString(), FixedincomeProcessDto.class);
//            one.setRowJson(ob.toJSONString());
//            fp.add(one);
//        }


        logger.info("fp{}",fp);
        return fp;
    }

    public String getCodeFromResponse(ResponseEntity<String> postForEntity, String interfaceName) throws
            Exception {
        String response = postForEntity.getBody();
        JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
        JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject(interfaceName + "Response")
                .getJSONObject(interfaceName + "Result");
        String code = result.getJSONObject("rt").getJSONObject("RE").getString("RC");
        logger.info("code{}",code);
        return code;
    }

    public String getTotalFromResponse(ResponseEntity<String> postForEntity, String interfaceName) throws
            Exception {
        String response = postForEntity.getBody();
        JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
        JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject(interfaceName + "Response")
                .getJSONObject(interfaceName + "Result");
        String total = result.getJSONObject("rt").getJSONObject("RE").getString("TotalPage");
        logger.info("total{}",total);
        return total;
    }

    public String getKeyFromLogin() {

        try {
            String requestBody = EncryptUtils.encryptString(getLoginBody());
            HttpHeaders loginHeader = header(requestBody.getBytes().length, FixedIncomeConstant.LOGON_INTERFACENAME);
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, loginHeader);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);
            logger.info("衡泰登录接口返回原始报文:" + postForEntity.getBody());
            String response = postForEntity.getBody();
            JSONObject resjson = XmlToJsonUtils.xmltoJson(response);
            JSONObject result = resjson.getJSONObject("Envelope").getJSONObject("Body").getJSONObject("MobileLogonResponse").getJSONObject("MobileLogonResult");
            String code = result.getJSONObject("rt").getJSONObject("RE").getString("RC");
            String key = "";
            if ("0".equals(code)) {
                key = result.getJSONObject("rt").getJSONObject("RE").getString("KEY");
            }
            logger.info("key{}",key);
            return key;
        } catch (Exception e) {
            logger.error("衡泰系统登录异常，请查看。", e);
            throw new RuntimeException("衡泰系统登录获取key异常，请查看。");
        }
    }


    private String getLoginBody() {
        String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Body><MobileLogon xmlns=\"http://www.xquant.com/\"><aUserCode>" +
                username +
                "</aUserCode><aPwd>" +
                "<![CDATA[" +
                password +
                "]]>" +
                "</aPwd><aMAC>|82:54:01:16:59:54|xirguolian|</aMAC></MobileLogon></soap:Body></soap:Envelope>";
        logger.info("loginbody"+xml);
        return xml;
    }


    /*
    deviceno:|82:54:01:16:59:54|895d6288e1034cb6|
soapaction:http://www.xquant.com/MobileGetTaskNodeLstByPageNew   --接口方法名
devicetype: LIO-AN00                               --设备型号
logonuser:Apptest                                  --用户代码
deviceid: |82:54:01:16:59:54|895d6288e1034cb6|     --设备编码 guid即可
content-type:text/xml; charset=utf-8
content-length:1368               --内容长度，调用不同的方法，长度不一样
host:r3698119m1.wicp.vip          --接口地址
connection:Keep-Alive
accept-encoding:gzip
cookie:ASP.NET_SessionId=bcivcn1jdmyk31qwponexrt3
user-agent:okhttp/3.11.0

     */
    private HttpHeaders header(int bodylen, String interfaceName) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("deviceno", "|82:54:01:16:59:54|xirguolian|");
        headers.add("soapaction", "http://www.xquant.com/" + interfaceName);
        headers.add("devicetype", "XIR-GUOLIAN");
        headers.add("logonuser", username);
        headers.add("deviceid", "|82:54:01:16:59:54|xirguolian|");
        MediaType type = MediaType.parseMediaType("text/xml; charset=utf-8");
        headers.setContentType(type);
        //headers.setContentLength(bodylen);
        headers.setHost(new InetSocketAddress(ip, port));
        headers.setConnection("Keep-Alive");
        headers.add("accept-encoding", "gzip");
        //headers.add("cookie", "ASP.NET_SessionId=bcivcn1jdmyk31qwponexrt3");
        headers.add("user-agent", "okhttp/3.11.0");
        return headers;
    }

    /**
     * 批量审批操作/MobileApproveTaskByNodeId_Batch
     *
     * @param key
     * @param nodeId
     * @param isAgree
     * @return
     */
    // 1同意2拒绝
    private String approveTaskHeader(String key, String nodeId, String isAgree, String userId) {

        SystemConfig config = systemConfigRepository.findByConfigCode(DictConstant.FIXED_OA_CHINESS_MAP);
        String mapValue = config.getConfigValue();
        JSONObject  jsonObject = JSONObject.parseObject(mapValue);
        Map<String,String> accountoaToChineseMap = JSONObject.parseObject(jsonObject.toJSONString(),new TypeReference<Map<String,String>>(){});

        StringBuffer sb = new StringBuffer();

        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header>" +
                "<soap:Body><MobileApproveTaskByNodeId_Batch xmlns=\"http://www.xquant.com/\">");
        sb.append("<aNodeIds>" + nodeId + "</aNodeIds><targetType>OTCTRADE</targetType>" +
                "<aAction>" + isAgree + "</aAction>" +
                "<actionUser>" + key + "</actionUser><actionNote>" + accountoaToChineseMap.get(userId) + "</actionNote>" +
                "<aDataTypeCurrent>0</aDataTypeCurrent>" +
                "<aCCRoleList></aCCRoleList></MobileApproveTaskByNodeId_Batch></soap:Body></soap:Envelope>");
        logger.info("移动审批批量审批操作接口请求报文:" + sb.toString());
        return sb.toString();
    }


    /**
     * 分页查询审批数据列表信息/MobileGetTaskNodeLstByPageNew
     *
     * @param key
     * @return
     */
    private String searchTaskHeader(String key, String pageNumber) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileGetTaskNodeLstByPageNew xmlns=\"http://www.xquant.com/\">");
        sb.append("<aPage>" + pageNumber + "</aPage><aTargetType>OTCTRADE</aTargetType>" +
                "<aUserCode>" + key + "</aUserCode>" +
                "<aBeg_date></aBeg_date><aEnd_date></aEnd_date><aDataType>0</aDataType><aGroupCode>0</aGroupCode><accid></accid><trdType></trdType><submitUser></submitUser></MobileGetTaskNodeLstByPageNew></soap:Body></soap:Envelope>");

        logger.info("taskHeader"+sb.toString());

        return sb.toString();
    }


    /**
     * 分页查询审批数据列表信息/MobileGetTaskNodeLstByPageNew
     *
     * @param key
     * @return
     */
    private String searchGroupTaskHeader(String key, String pageNumber, String groupCode) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileGetTaskNodeLstByPageNew xmlns=\"http://www.xquant.com/\">");
        sb.append("<aPage>" + pageNumber + "</aPage><aTargetType>OTCTRADE</aTargetType>" +
                "<aUserCode>" + key + "</aUserCode>" +
                "<aBeg_date></aBeg_date><aEnd_date></aEnd_date><aDataType>0</aDataType><aGroupCode>" + groupCode + "</aGroupCode><accid></accid><trdType></trdType><submitUser></submitUser></MobileGetTaskNodeLstByPageNew></soap:Body></soap:Envelope>");

        logger.info("groupTask"+sb.toString());

        return sb.toString();
    }


    /**
     * 查询审批数据分组信息/MobileGetTaskNodeGroup
     *
     * @param key
     * @return
     */
    private String getGroupCodeHeader(String key) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileGetTaskNodeGroup xmlns=\"http://www.xquant.com/\">" +
                "<aTargetType>OTCTRADE</aTargetType>" +
                "<aUserCode>" + key + "</aUserCode>" +
                "<aBeg_date></aBeg_date><aEnd_date></aEnd_date><aDataType>0</aDataType></MobileGetTaskNodeGroup></soap:Body></soap:Envelope>");

        logger.info("groupCode"+sb.toString());
        return sb.toString();
    }

    /**
     * 查询出差人员/MobileGetAllBusinessUser
     *
     * @param key
     * @return
     */
    private String getTripListHeader(String key) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileGetAllBusinessUser xmlns=\"http://www.xquant.com/\">" +
                "<aUserCode>" + key + "</aUserCode>" +
                "</MobileGetAllBusinessUser></soap:Body></soap:Envelope>");
        logger.info("tripList"+sb.toString());
        return sb.toString();
    }

    public String createOaflow(Map<String, Object> dataMap, String flowId) throws Exception {

        logger.info("开始创建流程，FlowId:" + flowId + ",参数:" + dataMap.toString() + ",时间:" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        String params = "flowId:" + flowId;
        //取得主必填字段，字段名称为转义后的
        Set<String> fields = metaFlowService.getMandatoryFields(flowId, "0");
        logger.debug("外层：" + fields.toString());
        //取得必填的明细字段，字段名称为转义后的
        Map<String, Set<String>> detailFields = metaFlowService.getMandatoryDetails(flowId);
        logger.debug("内层：" + detailFields.toString());
        //校验必填参数
        String paramsVerfication = metaFlowService.checkFLowParams(dataMap, fields, detailFields);

        String finalResult = "";
        if (paramsVerfication.equals(GatewayConstant.PARAMS_VERIFICATION)) {
            //组装创建流程请求报文
            FlowObject fo = addFlowService.operateOAMessage(dataMap, metaFlowService.getFlowMetaDataList(flowId), flowId);
            logger.info("创建流程调用参数为：" + JSONObject.toJSON(fo).toString());
            //调oa创建接口
            Map<String, String> resultMap = addFlowService.addOaFlow(JSONObject.toJSON(fo).toString());
            if (Integer.parseInt(resultMap.get("requestid")) > 0) {
                logger.info("完成流程创建，FlowId:" + flowId + ",流程requestid:" + resultMap.get("requestid").toString() + ",时间:" + DateUtils.getCurrentDate(DateUtils.formatSecond));
                finalResult = JSON.toJSONString(InterfaceResponse.returnSuccss(resultMap));
            } else {
                logger.error("流程创建失败，FlowId:" + flowId + ",流程requestid:" + resultMap.get("requestid").toString() + ",时间:" + DateUtils.getCurrentDate(DateUtils.formatSecond));
                throw new BusinessException(ExceptionConstant.BussinessException, "创建流程失败，需要咨询OA系统，流程ID:" + flowId + ",参数:" + dataMap.toString());
            }
        } else {
            logger.error("创建流程失败，FlowId:" + flowId + ",关键参数缺失:" + paramsVerfication + ",时间:" + DateUtils.getCurrentDate(DateUtils.formatSecond));
            throw new BusinessException(ExceptionConstant.BussinessException, "创建流程失败，流程ID:" + flowId + " ,缺失参数:" + paramsVerfication);
        }
        return finalResult;
    }


//***********************************************************以下方法接口未使用************************************

    /**
     * 查询单笔审批单审批流程图/MobileSingleTaskNodeTree
     *
     * @param key
     * @return
     */
    private String getTaskInfoHeader(String key, String taskId) {

        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "<soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileSingleTaskNodeTree xmlns=\"http://www.xquant.com/\">" +
                "<aUserCode>" + key + "</aUserCode><aTaskId>" + taskId + "</aTaskId></MobileSingleTaskNodeTree></soap:Body></soap:Envelope>");
        return sb.toString();
    }


    /**
     * 批量审批前检查/MobileCheckBeforeActionByNodeId_Batch
     *
     * @param key
     * @param nodeId
     * @return
     */
    private String checkBeforeActionHeader(String key, String nodeId) {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Header><ServiceCredential xmlns=\"http://www.xquant.com/\">" +
                "<X>" + username + "</X>" +
                "<Y>" + key + "</Y>" +
                "</ServiceCredential></soap:Header><soap:Body><MobileCheckBeforeActionByNodeId_Batch xmlns=\"http://www.xquant.com/\">" +
                "<aNodeIds>" + nodeId + "</aNodeIds>" +
                "<aUserCode>" + key + "</aUserCode><targetType>OTCTRADE</targetType><aDataTypeCurrent>0</aDataTypeCurrent></MobileCheckBeforeActionByNodeId_Batch></soap:Body></soap:Envelope>");
        return sb.toString();
    }


    public void checkBeforeAction(String nodeId) {
        try {
            String key = getKeyFromLogin();
            if (("").equals(key)) {
                return;
            }
            String requestBody = EncryptUtils.encryptString(checkBeforeActionHeader(key, nodeId));
            HttpHeaders header = header(requestBody.getBytes().length, "MobileCheckBeforeActionByNodeId_Batch");
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, header);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);

            logger.info("postEn"+postForEntity);
            String code = getCodeFromResponse(postForEntity, "MobileCheckBeforeActionByNodeId_Batch");
            if ("0".equals(code)) {

            } else {
                logger.error("衡泰系统检查接口返回有误，请查看。res=" + postForEntity.getBody());
            }
        } catch (Exception e) {
            logger.error("衡泰系统检查接口异常，请查看。", e);
            throw new RuntimeException("衡泰系统检查接口异常，请查看。");
        }
    }

    public void getTaskInfo(String taskId) {
        try {
            String key = getKeyFromLogin();
            if (("").equals(key)) {
                return;
            }
            String requestBody = EncryptUtils.encryptString(getTaskInfoHeader(key, taskId));
            HttpHeaders header = header(requestBody.getBytes().length, "MobileSingleTaskNodeTree");
            // 组装发送postForEntity请求
            HttpEntity<String> request = new HttpEntity<>(requestBody, header);
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);

            logger.info("posEnti"+postForEntity);
            String code = getCodeFromResponse(postForEntity, "MobileSingleTaskNodeTree");
            if ("0".equals(code)) {

            } else {
                logger.error("衡泰系统查询任务状态接口返回有误，请查看。res=" + postForEntity.getBody());
            }
        } catch (Exception e) {
            logger.error("衡泰系统查询任务状态接口异常，请查看。", e);
            throw new RuntimeException("衡泰系统查询任务状态接口异常，请查看。");
        }
    }

}
